package org.xiaojl.wechat.service;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.xiaojl.utils.HttpsClientHelp;
import org.xiaojl.utils.JsonUtil;
import org.xiaojl.utils.ToolUtil;
import org.xiaojl.wechat.WeChatConstants;
import org.xiaojl.wechat.WeChatKit;


@Service("weChatService")
public class WeChatService {
	private static final Logger log = LoggerFactory.getLogger(WeChatService.class);
	
	/**
	 * 获取access_token
	 */
	public String getWeChatAccessToken(){
		String path = Class.class.getClass().getResource("/").getPath() ;
		String fileName = "/access_token.txt";
		log.debug("获取AccessToke - Token文档路径："+path +"文件名称："+fileName);
		String spiltStr = "&&&&&";
		String ret = "";
		try {
			String str = WeChatKit.readTxtFile(path+fileName);
			if(ToolUtil.isNotEmpty(str)){
				String[] arr = str.split(spiltStr);
				String times = arr[1];
				long nowTimes = System.currentTimeMillis();
				
				if(Long.parseLong(times) > nowTimes){ 
					log.info("获取AccessToke - Token还未过期，可以使用，Token="+arr[0]);
					return arr[0];
				}
				log.info("获取AccessToke - Token已过期，重新获取！");
			}
			
			List<NameValuePair> parms = new ArrayList<NameValuePair>();
			parms.add(new BasicNameValuePair("appid", WeChatConstants.APP_ID));
			parms.add(new BasicNameValuePair("secret", WeChatConstants.SECRET));
			parms.add(new BasicNameValuePair("grant_type", "client_credential"));

			String getTokenRUL = WeChatConstants.BASE_URL+"/cgi-bin/token";
			HttpsClientHelp client = new HttpsClientHelp();
			String resp = client.byWxPostMethodToHttpEntity(getTokenRUL, parms, "UTF-8");
			log.info("获取AccessToke - 返回结果:" + resp);
			if (resp != null && resp.length() != 0) {
				if (resp.indexOf("access_token") > 0) {
					Map<String, String> map = JsonUtil.str2Map(resp);
					ret = map.get("access_token");
					String expiesIn = map.get("expires_in"); //凭证有效时间，单位：秒
					//5分钟的切换时间空间
					long expiesTimes = System.currentTimeMillis()+(Long.parseLong(expiesIn)-6*30)*1000;
					
					PrintWriter pw = null;
					try {
						pw = new PrintWriter(new FileWriter(path+fileName));
						pw.print(ret+spiltStr+expiesTimes);
					} catch (IOException e) {
						log.error("获取AccessToke - token信息写入文件失败！",e);
					}finally{
						if(pw!=null){
							pw.flush();
							pw.close();
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("获取AccessToke - 出现异常！",e);
		}
		
		return ret;
	}


	/**
	 * 
	 * 1、通过code换取网页授权access_token：access_token、openid【此access_token与基础支持的access_token不同】<br>
	 * 2、拉取用户信息(需scope为 snsapi_userinfo)<br>
	 * 
	 * @param weChatCode
	 * @return Map<String, String>: <br>
	 *  	openid	用户的唯一标识<br>
			nickname	用户昵称<br>
			sex	用户的性别，值为1时是男性，值为2时是女性，值为0时是未知<br>
			province	用户个人资料填写的省份<br>
			city	普通用户个人资料填写的城市<br>
			country	国家，如中国为CN<br>
			headimgurl	用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空。若用户更换头像，原有头像URL将失效。<br>
			privilege	用户特权信息，json 数组，如微信沃卡用户为（chinaunicom）<br>
			unionid	只有在用户将公众号绑定到微信开放平台帐号后，才会出现该字段。<br>
	 */
	public Map<String, String> getUserInfoByWeChatCode(String weChatCode) {
		try {
			//1、通过code换取网页授权access_token【此access_token与基础支持的access_token不同】
			List<NameValuePair> parms = new ArrayList<NameValuePair>();
			parms.add(new BasicNameValuePair("appid", WeChatConstants.APP_ID));
			parms.add(new BasicNameValuePair("secret", WeChatConstants.SECRET));
			parms.add(new BasicNameValuePair("code", weChatCode));
			parms.add(new BasicNameValuePair("grant_type", "authorization_code"));
			
			//https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 
			String getTokenRUL = WeChatConstants.BASE_URL+"/sns/oauth2/access_token";
			HttpsClientHelp client = new HttpsClientHelp();
			String resp = client.byWxPostMethodToHttpEntity(getTokenRUL, parms, "UTF-8");
			log.info("获取微信用户信息 - code换取网页授权Token，返回结果:" + resp);
			if(resp.contains("openid")){
				Map<String, String> openIdMap = JsonUtil.str2Map(resp);
				String refreshToken = openIdMap.get("refresh_token");
				
				//2、拉取用户信息(需scope为 snsapi_userinfo)
				Map<String, String> weChatUserInfo = getUserInfoByRefreshToken(refreshToken);
				
				//返回
				return weChatUserInfo;
			}
			
		} catch (Exception e) {
			log.error("获取微信用户信息 - 刷新access_token - 出现异常！",e);
		}
		
		return null;
	}


	/**
	 * 刷新access_token
	 * 
	 * @param refreshToken	用户刷新access_token
	 * @return
	 */
	private Map<String, String> getUserInfoByRefreshToken(String refreshToken) {
		try {
			/**
			 * 1、刷新access_token，由于access_token拥有较短的有效期，当access_token超时后，
			 * 可以使用refresh_token进行刷新，refresh_token有效期为30天，当refresh_token失效之后，需要用户重新授权。
			 */
			List<NameValuePair> parms = new ArrayList<NameValuePair>();
			parms.add(new BasicNameValuePair("appid", WeChatConstants.APP_ID));
			parms.add(new BasicNameValuePair("refresh_token", refreshToken));
			parms.add(new BasicNameValuePair("grant_type", "refresh_token"));
			
			//https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN 
			String getTokenRUL = WeChatConstants.BASE_URL+"/sns/oauth2/refresh_token";
			HttpsClientHelp client = new HttpsClientHelp();
			String resp = client.byWxPostMethodToHttpEntity(getTokenRUL, parms, "UTF-8");
			log.info("获取微信用户信息 - 刷新access_token，返回结果:" + resp);
			if(resp.contains("openid")){
				Map<String, String> openIdMap = JsonUtil.str2Map(resp);
				//用户唯一标识，请注意，在未关注公众号时，用户访问公众号的网页，也会产生一个用户和公众号唯一的OpenID
				String openId = openIdMap.get("openid");
				String openIdAccessToken = openIdMap.get("access_token");
				
				/**
				 * 2、拉取用户信息(需scope为 snsapi_userinfo)
				 */
				Map<String, String> weChatUserInfo = getUserInfoByOpenId(openId,openIdAccessToken);
				
				return weChatUserInfo;
			}
		} catch (Exception e) {
			log.error("获取微信用户信息 - 刷新access_token - 出现异常！",e);
		}
		return null;
	}


	/**
	 * 拉取用户信息
	 * @param openId	用户的唯一标识
	 * @param openIdAccessToken	网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
	 * @return
	 */
	private Map<String, String> getUserInfoByOpenId(String openId,
			String openIdAccessToken) {
		try {
			List<NameValuePair> parms = new ArrayList<NameValuePair>();
			parms.add(new BasicNameValuePair("openid", openId));
			parms.add(new BasicNameValuePair("access_token", openIdAccessToken));
			parms.add(new BasicNameValuePair("lang", "zh_CN"));
			
			// https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN  
			String getTokenRUL = WeChatConstants.BASE_URL+"/sns/userinfo";
			HttpsClientHelp client = new HttpsClientHelp();
			String resp = client.byWxPostMethodToHttpEntity(getTokenRUL, parms, "UTF-8");
			log.info("获取微信用户信息 - 拉取用户信息，返回结果:" + resp);
			if(resp.contains("openid")){
				
				/**
				 *  openid	用户的唯一标识
					nickname	用户昵称
					sex	用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
					province	用户个人资料填写的省份
					city	普通用户个人资料填写的城市
					country	国家，如中国为CN
					headimgurl	用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空。若用户更换头像，原有头像URL将失效。
					privilege	用户特权信息，json 数组，如微信沃卡用户为（chinaunicom）
					unionid	只有在用户将公众号绑定到微信开放平台帐号后，才会出现该字段。
				 */
				Map<String, String> weChatUserInfo = JsonUtil.str2Map(resp);
				
				return weChatUserInfo;
			}
		} catch (Exception e) {
			log.error("获取微信用户信息 - 拉取用户信息 - 出现异常！",e);
		}
		return null;
	}
}
